/*
 * Copyright 2018-present KunMinX
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nsgf.library.ui.page;

import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Debug;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.ViewModel;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.kunminx.architecture.ui.scope.ViewModelScope;
import com.zhht.htzx.R;
import com.nsgf.library.base.BaseApplication;
import com.nsgf.library.base.DataBindingNsgfActivity;
import com.nsgf.library.data.repository.ApiException;
import com.nsgf.library.data.response.manager.NetworkStateManager;
import com.nsgf.library.utils.AdaptScreenUtils;
import com.nsgf.library.utils.BarUtils;
import com.nsgf.library.utils.CustomToast;
import com.nsgf.library.utils.DialogController;
import com.nsgf.library.utils.DialogUtil;
import com.nsgf.library.utils.SPUtil;
import com.nsgf.library.utils.ScreenUtils;
import com.nsgf.library.utils.SpKey;
import com.nsgf.library.utils.ToastUtils;
import com.nsgf.library.utils.Utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Locale;

import javax.net.ssl.SSLHandshakeException;

import retrofit2.HttpException;

/**
 * Create by GC at 24/9/21
 */
public abstract class BaseActivity extends DataBindingNsgfActivity implements View.OnClickListener
        , LocationListener {

    private final ViewModelScope mViewModelScope = new ViewModelScope();


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        BarUtils.setStatusBarColor(this, Color.TRANSPARENT);
        BarUtils.setStatusBarLightMode(this, true);
        super.onCreate(savedInstanceState);

        getLifecycle().addObserver(NetworkStateManager.getInstance());

        //TODO tip 1: DataBinding 严格模式（详见 DataBindingActivity - - - - - ）：
        // 将 DataBinding 实例限制于 base 页面中，默认不向子类暴露，
        // 通过这方式，彻底解决 View 实例 Null 安全一致性问题，
        // 如此，View 实例 Null 安全性将和基于函数式编程思想的 Jetpack Compose 持平。

        bindViews();
//        checkIDADebug(this);
    }

    public void checkIDADebug(Activity context) {
        // 判断一  是否可调试
        if (isDebuggable(context)) {
            alertAndExit(context);
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean isIDADebugging = false;
                while (!isIDADebugging) {
                    try {
                        // 判断二  23946端口是否被占用
                        Socket s = new Socket();
                        s.bind(new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), 23946));
                        s.close();
                        // 判断三  判断TracerPid是否为0  判断四 调试器是否连接
                        if (isUnderTraced() || Debug.isDebuggerConnected()) {
                            isIDADebugging = true;
                        } else {
                            // 如果通过了检测，则8秒后再次检测
                            Thread.sleep(8000);
                        }
                    } catch (Exception e) {
                        // 如果23946端口已被占用，会报异常
                        e.printStackTrace();
                        isIDADebugging = true;
                    }
                }
                alertAndExit(context);
            }
        }).start();
    }

    /**
     * 判断当前应用是否是debug状态
     *
     * @param context
     * @return
     */
    private static boolean isDebuggable(Context context) {
        try {
            ApplicationInfo info = context.getApplicationInfo();
            return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 当我们使用Ptrace方式跟踪一个进程时，目标进程会记录自己被谁跟踪，可以查看/proc/pid/status看到这个信息,而没有被调试的时候TracerPid为0
     * <p>
     * 返回 true 表示在被调试， false没有被调试
     *
     * @return
     */
    private static boolean isUnderTraced() {
        String processStatusFilePath = String.format(Locale.US, "/proc/%d/status", android.os.Process.myPid());
        File procInfoFile = new File(processStatusFilePath);
        try {
            BufferedReader b = new BufferedReader(new FileReader(procInfoFile));
            String readLine;
            while ((readLine = b.readLine()) != null) {
                if (readLine.contains("TracerPid")) {
                    String[] arrays = readLine.split(":");
                    if (arrays.length == 2) {
                        int tracerPid = Integer.parseInt(arrays[1].trim());
                        if (tracerPid != 0) {
                            return true;
                        }
                    }
                }
            }

            b.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }
    //TODO tip 2: Jetpack 通过 "工厂模式" 实现 ViewModel 作用域可控，
    //目前我们在项目中提供了 Application、Activity、Fragment 三个级别的作用域，
    //值得注意的是，通过不同作用域 Provider 获得 ViewModel 实例非同一个，
    //故若 ViewModel 状态信息保留不符合预期，可从该角度出发排查 是否眼前 ViewModel 实例非目标实例所致。


    protected <T extends ViewModel> T getActivityScopeViewModel(@NonNull Class<T> modelClass) {
        return mViewModelScope.getActivityScopeViewModel(this, modelClass);
    }

    protected <T extends ViewModel> T getApplicationScopeViewModel(@NonNull Class<T> modelClass) {
        return mViewModelScope.getApplicationScopeViewModel(modelClass);
    }

    @Override
    public Resources getResources() {
        if (ScreenUtils.isPortrait()) {
            return AdaptScreenUtils.adaptWidth(super.getResources(), 375);
        } else {
            return AdaptScreenUtils.adaptHeight(super.getResources(), 720);
        }
    }

    protected void toggleSoftInput() {
        InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }

    protected void openUrlInBrowser(String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }


    /**
     * 绑定默认的标准TitleBar  如果使用自定义的TitleBar只需要避免使用下面的id就OK
     */
    protected void bindViews() {
        backBtn = (ImageView) findViewById(R.id.title_bar_back);
        menuBtn = (ImageView) findViewById(R.id.title_bar_menu);
        titleTv = (TextView) findViewById(R.id.title_bar_root);

        title_bar_right = (ImageView) findViewById(R.id.title_bar_clear);


        if (backBtn != null)
            backBtn.setOnClickListener(this);
        if (menuBtn != null)
            menuBtn.setOnClickListener(this);
        if (title_bar_right != null)
            title_bar_right.setOnClickListener(this);

//        if (titleTv != null && backBtn != null)
//            backBtn.setColorFilter(titleTv.getCurrentTextColor());
        registerMessageReceiver();
    }


    /**
     * @param v
     * @deprecated not security method.Use {@link BaseActivity#onClickSecurity(View)}
     */
    @Deprecated
    @Override
    public void onClick(View v) {
        try {
            onClickSecurity(v);
        } catch (Exception e) {
            e.getMessage();
        }
    }

    /**
     * 返回按钮
     */
    protected ImageView backBtn;
    /**
     * 右上角的功能按钮
     */
    protected ImageView menuBtn;
    /**
     * 标题栏
     */
    protected TextView titleTv;


    protected ImageView title_bar_right;

    /**
     * 防止点击事件出错导致程序崩溃,提供了相对安全的事件响应容器
     *
     * @param v
     */
    protected void onClickSecurity(View v) {
        if (backBtn != null && backBtn.getId() == v.getId()) {
            onBackPressed();
        } else if (menuBtn != null && menuBtn.getId() == v.getId()) {
            onMenuClicked();
        }
    }

    protected void onMenuClicked() {

    }

    protected void onTitleClicked() {

    }

    public class MessageReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {

                    Dialog dialog = new Dialog(context, R.style.dialogstyle);
                    dialog.setContentView(R.layout.dialog_login_user_type);
                    dialog.show();
                } else if (MESSAGE_RECEIVED_DIALOG_CONTROLLER_ACTION.equals(intent.getAction())) {
                    getController().displayLoading();
                }
            } catch (Exception e) {
            }
        }

    }

    private MessageReceiver mMessageReceiver;
    public static final String MESSAGE_RECEIVED_ACTION = "com.nsgf.library.MESSAGE_RECEIVED_ACTION";
    public static final String MESSAGE_RECEIVED_DIALOG_CONTROLLER_ACTION = "com.nsgf.library.DIALOG_CONTROLLER_ACTION";
    public static final String MESSAGE_RECEIVED_ACTION_BOTTOM = "com.nsgf.library.MESSAGE_RECEIVED_ACTION_BOTTOM";
    public static final String MESSAGE_RECEIVED_ACTION_BOTTOM_NUMBER = "com.nsgf.library.MESSAGE_RECEIVED_ACTION_BOTTOM_NUMBER";

    public void registerMessageReceiver() {

        mMessageReceiver = new MessageReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(MESSAGE_RECEIVED_ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter);
    }


    DialogController dialogController;

    /**
     * 缺省的网络请求的流程框架 可以自定义
     *
     * @return BaseController
     */
    public DialogController getController() {
        if (dialogController == null) {
            dialogController = new DialogController(this);
        }
        return dialogController;
    }

    public void startLocation() {
        startLocation(false);
    }

    /**
     * 发起定位
     *
     * @param realTime 是否实时定位
     */
    public void startLocation(boolean realTime) {
        if (null == locationManager) {
            locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        }
        // 检查是否已经给予位置权限
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            // 请求位置更新
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0x123);
                return;
            }
            // 请求位置更新，最小时间间隔和最小距离变化后更新
            if (realTime) {
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, this);
            } else {
                locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, null);
            }
        } else {
            // 提示用户开启GPS
            ToastUtils.showLongToast("请打开定位权限");
            if (realTime)
                showMissingPermissionDialog();
        }
    }


    /**
     * 显示提示信息
     *
     * @since 2.5.0
     */
    private void showMissingPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.notifyTitle);
        builder.setMessage(R.string.notifyMsg);

        // 拒绝, 退出应用
        builder.setNegativeButton(R.string.cancel,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                });

        builder.setPositiveButton(R.string.setting,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startAppSettings();
                    }
                });

        builder.setCancelable(false);

        builder.show();
    }

    /**
     * 启动应用的设置
     *
     * @since 2.5.0
     */
    public void startAppSettings() {
        Intent intent = new Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getController().dismissLoading();
        if (null != locationManager)
            locationManager.removeUpdates(this);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == 0x123) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 用户授予了权限，执行操作
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    // TODO: Consider calling
                    //    ActivityCompat#requestPermissions
                    // here to request the missing permissions, and then overriding
                    //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                    //                                          int[] grantResults)
                    // to handle the case where the user grants the permission. See the documentation
                    // for ActivityCompat#requestPermissions for more details.
                    return;
                }
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 100, this);
            } else {
                // 用户拒绝了权限，提示或处理拒绝逻辑
                // 提示用户开启GPS
                Toast.makeText(this, "请打开定位权限", Toast.LENGTH_LONG).show();
            }
        }
    }


    public LocationManager locationManager;

    @Override
    public void onLocationChanged(@NonNull Location location) {

        // 当位置更新时，这里处理位置信息
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();

        SPUtil.put(SpKey.KEY_LATITUDE, String.valueOf(latitude), this);
        SPUtil.put(SpKey.KEY_LONGITUDE, String.valueOf(longitude), this);
        Log.e("==============", latitude + "," + longitude);
    }


    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // 处理状态变化
    }

    @Override
    public void onProviderEnabled(String provider) {
        // 处理提供者启用
    }

    @Override
    public void onProviderDisabled(String provider) {
        // 处理提供者禁用
    }

    public void Error(Throwable e) {
        String error = null;
        try {

            if (e instanceof SocketTimeoutException) {//请求超时
                error = "网络连接超时";
            } else if (e instanceof ConnectException) {//网络连接超时
                error = "网络连接超时";
            } else if (e instanceof SSLHandshakeException) {//安全证书异常
                error = "安全证书异常";
            } else if (e instanceof HttpException) {//请求的地址不存在
                int code = ((HttpException) e).code();
                if (code == 504) {
                    error = "网络异常，请检查您的网络状态";
                } else if (code == 502) {
                    error = e.getMessage();
                } else if (code == 404) {
                    error = "请求的地址不存在";
                } else {
                    error = "请求失败";
                }
            } else if (e instanceof UnknownHostException) {//域名解析失败
                error = "域名解析失败";
            } else
                error = e.getMessage();
            Toast.makeText(BaseApplication.getInstance(), error, Toast.LENGTH_SHORT).show();

        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }


    public String getErrorMsg(Throwable e) {
        String error = null;
        try {

            if (e instanceof SocketTimeoutException) {//请求超时
                error = "网络连接超时";
            } else if (e instanceof ConnectException) {//网络连接超时
                error = "网络连接超时";
            } else if (e instanceof SSLHandshakeException) {//安全证书异常
                error = "安全证书异常";
            } else if (e instanceof HttpException) {//请求的地址不存在
                int code = ((HttpException) e).code();
                if (code == 504) {
                    error = "网络异常，请检查您的网络状态";
                } else if (code == 502) {
                    error = e.getMessage();
                } else if (code == 404) {
                    error = "请求的地址不存在";
                } else {
                    error = "请求失败";
                }
            } else if (e instanceof UnknownHostException) {//域名解析失败
                error = "域名解析失败";
            } else {
                error = e.getMessage();
            }
            return error;

        } catch (Exception e2) {
            e2.printStackTrace();
            return "";
        }
    }


    /***
     * 此方法用于改变背景的透明度，从而达到“变暗”的效果
     */
    public static void backgroundAlpha(Activity activity, float bgAlpha) {
        WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
        lp.alpha = bgAlpha; //0.0-1.0
        activity.getWindow().setAttributes(lp);
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    public void showToast(final String txt) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                CustomToast.showToast(Utils.getApp().getApplicationContext(), txt);
            }
        });
    }

    /**
     * 如果检测到 IDA动态调试， 提示用户并关闭程序
     *
     * @param context
     */
    private static void alertAndExit(Activity context) {
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                AlertDialog alertDialog = new AlertDialog.Builder(context).setTitle("温馨提示").setMessage("当前应用在调试状态，为保证应用安全，10秒后将自动退出应用，请先退出调试状态再打开APP，感谢理解。")
                        .setPositiveButton("确定（10s）", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                exitApp(context);
                            }
                        }).setCancelable(false).create();
                alertDialog.show();
                new CountDownTimer(10000, 1000) {  //11秒倒计时，每秒执行一次
                    public void onTick(long millisUntilFinished) {  //每秒执行一次进该方法
                        alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setText("确定（" + (millisUntilFinished / 1000 + 1) + "s）");
                    }

                    public void onFinish() {  //倒计时结束。
                        exitApp(context);
                    }
                }.start();
            }
        });
    }

    /**
     * 退出APP
     *
     * @param context
     */
    private static void exitApp(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ActivityManager activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.AppTask> appTaskList = activityManager.getAppTasks();
            for (ActivityManager.AppTask appTask : appTaskList) {
                appTask.finishAndRemoveTask();
            }
        } else {
            android.os.Process.killProcess(android.os.Process.myPid());
        }

    }


    public boolean isNotificationPermissionGranted() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return notificationManager.areNotificationsEnabled();
        }
        return true; // 在较低版本中默认允许
    }

    public void showPermissionDialog() {
        new AlertDialog.Builder(this)
                .setTitle("启用通知")
                .setMessage("启用通知以便获取最新消息和更新。")
                .setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", getPackageName(), null);
                        intent.setData(uri);
                        startActivity(intent);
                    }
                })
                .setNegativeButton("取消", null)
                .show();
    }
}
